package com.zyk.scaffold.core.config.exception;

import com.alibaba.fastjson.JSON;
import com.zyk.scaffold.common.basic.BasicException;
import com.zyk.scaffold.core.domain.Result;
import com.zyk.scaffold.common.enums.CommonErrorCodeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.web.error.ErrorAttributeOptions;
import org.springframework.boot.web.reactive.error.DefaultErrorAttributes;
import org.springframework.cloud.gateway.support.NotFoundException;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.server.ResponseStatusException;

import java.util.Map;

@Slf4j
@Configuration
public class LocalReactiveErrorAttributes extends DefaultErrorAttributes {
    @Override
    public Map<String, Object> getErrorAttributes(ServerRequest request, ErrorAttributeOptions options) {
        Throwable error = getError(request);
        if (error != null) {
            Result<Object> result = null;
            if (error instanceof BasicException) {
                result = Result.error((BasicException) error);
            }else if (error instanceof NotFoundException) {
                result = Result.error(CommonErrorCodeEnum.SERVER_NOT_FOUND);
            }else if (error instanceof ResponseStatusException) {
                log.error("LocalReactiveErrorAttributes ResponseStatusException", error);
                result = buildResponseStatusResult((ResponseStatusException)error);
            }else if (error instanceof Exception) {
                log.error("LocalReactiveErrorAttributes error", error);
                result = Result.error(CommonErrorCodeEnum.SERVER_ERROR);
            }
            if (result != null){
//                StringWriter stackTrace = new StringWriter();
//                error.printStackTrace(new PrintWriter(stackTrace));
//                stackTrace.flush();
//                result.setStack(RandomStringUtils.randomAlphanumeric(10) + Base64.getEncoder().encodeToString(stackTrace.toString().getBytes(StandardCharsets.UTF_8)));
                Map<String, Object> innerMap = JSON.parseObject(JSON.toJSONString(result)).getInnerMap();
                innerMap.put("status", HttpStatus.OK.value());
                return innerMap;
            }
        }
        return super.getErrorAttributes(request, options);
    }

    private Result<Object> buildResponseStatusResult(ResponseStatusException error) {
        Result<Object> result = null;
        HttpStatus status = error.getStatus();
        switch (status){
            case NOT_FOUND: result = Result.error(CommonErrorCodeEnum.SERVER_NOT_FOUND);break;
            case METHOD_NOT_ALLOWED: result = Result.error(CommonErrorCodeEnum.SERVER_METHOD_NOT_ALLOWED);break;
            default:result = Result.error(CommonErrorCodeEnum.SERVER_ERROR);break;
        }
        return result;
    }
}
